package router

import (
	"errors"
	"fmt"
	"os"

	"gitee.com/liukexing/isrn/api"
	"gitee.com/liukexing/isrn/api/advanced"
	"gitee.com/liukexing/isrn/api/network"
	"gitee.com/liukexing/isrn/api/tool"
)

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"

	ci "gitee.com/liukexing/isrn/go-libp2p-crypto"
)

const ()

var (
	sh         *shell.Shell
	nodeCyprto NodeCyprto
	nodeid     string
	headbytes  []byte
	headlen    int = 8
)

//初始化本地Ipfs API
func initClient(path ...string) error {
	if len(path) > 1 {
		return errors.New("Too many path arguments")
	}
	if len(path) == 1 {
		if err := shell.SetIPFSEnv(path[0]); err != nil {
			return err
		}
	}
	sh = shell.NewLocalShell()
	if sh == nil {
		return errors.New("initClient Failed")
	}
	return nil
}

//初始化Ipfs API
func initClientUrl(url string) (*shell.Shell, error) {
	sh = shell.NewShell(url)
	if sh == nil {
		return nil, errors.New("initClient Failed")
	}
	return sh, nil
}

//初始化路由节点密钥值
func initNodeCyprto() error {
	id := network.IDCommand{*sh}
	r, err := id.ID()
	if err != nil {
		return err
	}
	nodeid = r.ID
	//获取节点公钥
	publicBytes, err := base64.StdEncoding.DecodeString(r.PublicKey)
	if err != nil {
		return err
	}

	pubkey, err := ci.UnmarshalPublicKey(publicBytes)
	if err != nil {
		return err
	}
	headbytes, err = pubkey.Bytes()
	if err != nil {
		return err
	}
	nodeCyprto.Pk = pubkey
	//获取节点私钥
	privateBytes, err := base64.StdEncoding.DecodeString(r.PrivateKey)
	if err != nil {
		return err
	}
	privkey, err := ci.UnmarshalPrivateKey(privateBytes)
	if err != nil {
		return err
	}
	nodeCyprto.Sk = privkey
	//生成数据加解密密钥
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return err
	}
	pk := &priv.PublicKey
	nodeCyprto.Rsk.SetSk(*priv)
	nodeCyprto.Rpk.SetK(*pk)
	return nil
}

//初始化路由环境
func initRouterEnv(port int) error {
	config := &tool.ConfigCommand{*sh}
	_, err := config.ConfigSet("Experimental.Libp2pStreamMounting", "true", true)
	if err != nil {
		return err
	}
	p2p := &advanced.P2pCommand{*sh}
	_, err = p2p.ListenerOpen("Route", fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))
	if err != nil {
		fmt.Fprintf(os.Stdout, "initRouterEnv Warn:%s", err.Error())
	}
	return nil
}

func StartRouter(path string, routerport int) error {
	if err := initClient(path); err != nil {
		return err
	}
	if err := initNodeCyprto(); err != nil {
		return err
	}
	if err := initRouterEnv(routerport); err != nil {
		return err
	}

	go startListen()
	go startConnect()
	go messageLoop()
	return nil
}
